<?php
// this file can  be only included, not used directly
if (__FILE__ == $_SERVER['SCRIPT_FILENAME']) exit;

/**
 * Calcualtes the SHA1 for a file. If there are errors during calculation,
 * an entry is written to the screen/logfile and the script is terminated
 * @param $sFilename
 * @return string
 */
function get_file_sha1($sFilename, $sBaseDir) {
	$sha1 = sha1_file($sFilename);
	if (!$sha1) {
		logdata("ERROR: Failed to calculate SHA1 for the file $sFilename!", 0);
		die_on_error('Failed to calculate SHA1 for file');
	}
	$sFilename = exclude_basedir($sFilename, $sBaseDir);
	return "F $sha1 $sFilename";
}

/**
 * Calculates the SHA1 recursively starting from a given directory.
 * Returns an array containing one entry per directory / file 
 * @param $sDirectory
 * @return array
 */
function get_file_sha1_recursive($sDirectory, $sBaseDir) {
	$aResult = array();
	$aResult[] = 'D ' . sha1('') . ' ' . exclude_basedir($sDirectory, $sBaseDir);
	foreach (glob($sDirectory . '/{,.}*', GLOB_BRACE) as $sFilename) {
		$sFilename = basename($sFilename);
		if ('.' == $sFilename[0]) continue;
		$sFilename =  $sDirectory . '/' . $sFilename;
		if (is_dir($sFilename)) {
			$aResult = array_merge($aResult, get_file_sha1_recursive($sFilename, $sBaseDir));		
		}
		else {
			$aResult[] = get_file_sha1($sFilename, $sBaseDir);
		}
	}
	return $aResult;
}

function exclude_basedir($sFilename, $sBaseDir) {
	$sFilename = realpath($sFilename);
	$sBaseDir  = realpath($sBaseDir);
	if (!preg_match("/[\\/\\\\]$/", $sBaseDir)) $sBaseDir .= '/';
	$sFilename = str_replace("\\", '/', $sFilename);
	return substr($sFilename, strlen($sBaseDir));
}

/**
 * Calculates the hashes for a basedir used for update
 * SHA1 is calculated for each template file + config.txt (we don't touch config.local) 
 */
function calculate_file_hashes($sBaseDir) {
	$aFileHashes = array();				
	$aFileHashes[] = get_file_sha1("$sBaseDir/config.txt", $sBaseDir);
	$sTemplateDir = $sBaseDir . '/templates';
	foreach (glob($sTemplateDir . '/*') as $sFilename) {
		$sFilename = basename($sFilename);
		if (!preg_match('/^\d+$/D', $sFilename)) continue;
		$sFilename = $sTemplateDir . '/' . $sFilename;
		if (!is_dir($sFilename)) continue;
		$aFileHashes = array_merge($aFileHashes, get_file_sha1_recursive($sFilename, $sBaseDir));
	}
	return join("\x0d\x0a", $aFileHashes); 
}

/**
 * Parses a line of the format F|D SHA1 filename. Returns false if it can't parse the line 
 * @return boolean
 */
function parse_update_line($sLine, &$sType, &$sSHA1, &$sFilename) {
	if (!preg_match('/^([FD]) ([0-9a-f]{40}) (.*)$/', $sLine, $aMatches)) return false;
	$sType     = $aMatches[1];
	$sSHA1     = $aMatches[2];
	$sFilename = $aMatches[3];
	return true;
}

/**
 * Parses a collection of lines separated by \x0d\x0a
 * @param $sLines
 * @return array
 */
function parse_update_lines($sLines) {
	$aResult = array();
	foreach(explode("\x0d\x0a", $sLines) as $sLine) {
		if (!parse_update_line($sLine, $sType, $sSHA1, $sName)) continue;
		$aResult[$sName] = array(
			'sha1' => $sSHA1,
			'type' => $sType,
		);
	}
	return $aResult;
}